module display_bus_02(

    input  wire             sclk                ,
    input  wire             resetb              ,
    input  wire             clk_mcu             ,
    input  wire             time_1s             ,
    input  wire             time_15ms           ,
    input  wire             time_250ms          ,
    
    //mcu ahb->apb  
    input  wire [3:0]       apb_sel             ,
    input  wire [31:0]      apb_addr            ,
    input  wire             apb_rw_en           ,
    input  wire [31:0]      apb_wdata           ,
    output wire [31:0]      apb_rdata0          ,  
    output wire [31:0]      apb_rdata1          , 
    output wire [31:0]      apb_rdata2          , 
    output wire [31:0]      apb_rdata3          , 

    //mcu GPIO
    output wire [7:0]       GPIO0_I             ,
    input  wire [7:0]       GPIO0_O             ,
    input  wire [7:0]       nGPEN0              ,
            
    output wire [7:0]       GPIO1_I             ,
    input  wire [7:0]       GPIO1_O             ,
    input  wire [7:0]       nGPEN1              ,
            
    output wire [7:0]       GPIO2_I             ,
    input  wire [7:0]       GPIO2_O             ,
    input  wire [7:0]       nGPEN2              ,
    //和通讯模块接口

    output reg              mcu_rec_end         ,
    output reg  [1:0]       fpga_flag_next      ,


     //给显示逻辑的参数设置
    output reg              set_d_ok            ,
    output wire [15:0]      set_addr            ,
    output wire [7:0]       set_data            ,

     //扩展接口
    input  wire [7:0]       sys_state_data      ,

    //
    output reg              id_is_valid         ,
    output reg  [63:0]      id                  ,

    //
    output reg              lock_enable         ,
    output reg  [31:0]      lock                ,

    //逐点调整数据
    input  wire             I_sdram_ready       ,
    output reg              O_adjust_start      ,
//    output reg         O_sdram_refresh_en,

    //和主控模块接口
    output reg              init_mode           ,
//    output reg         init_end        ,
    output reg              reboot_en           ,
    output reg              comm_en             ,
//    output reg         reconfig_en     ,
    output reg  [1:0]       reboot_sel          ,
//    output reg         reconfig_adjust_en  ,
    output reg              reconfig_pll_en     ,

    input  wire             frame_start         ,
    input  wire             key_in              ,
    output reg              key_out             ,

    output wire [9:0]       ram_waddr_rgb       ,
    output wire [31:0]      ram_wdata_rgb       ,
    output reg              ram_wr_rgb          ,
    input  wire             kp_busy             ,

    output wire [31:0]      sdram_ram_data_w    ,
    input  wire [31:0]      sdram_ram_data_r    ,
    output wire [ 9:0]      sdram_ram_addr      ,
    output reg              sdram_ram_addr_wren ,
    
    output reg  [23:0]      sdram_addr_start    ,
    output reg              sdram_wr_or_rd      ,
    output reg              sdram_req           ,
    input  wire             sdram_busy          ,
    output reg  [10:0]      sdram_rw_len        ,
    
    
    output wire [31:0]      tout
);
//**********************************************/
//        信号定义
/************************************************/
reg         reconfig_pll_en_dly;
reg         reboot_flag;
reg  [1:0]  reboot_cnt;
reg         reboot_en_tmp;

wire  [1:0]  ext_d_ok ;
reg   [15:0] ext_addr ;


reg [1:0]key_cnt;
always @(posedge sclk or negedge resetb) begin
    if (!resetb)
        key_cnt <= 'b0;
    else if( key_in )
        key_cnt <= 'b0;
    else if( key_cnt[1]==0 && time_15ms )
        key_cnt <= key_cnt + 1;
    else 
        key_cnt <= key_cnt ;
end

assign GPIO2_I[6] = key_cnt[1] ;


wire      wr_en_t;
reg  [15:0]wr_en;

always@ (posedge sclk) begin
    if(apb_rw_en)begin
        wr_en <= 16'hffff;
    end
    else begin
        wr_en <= 16'h0000;
    end
end


reg [15:0]sel_ok;
always@ (posedge sclk) begin
    case(apb_addr[27:24])
    4'd0:  begin
         sel_ok <= 16'b0000_0000_0000_0001 ;
    end
    4'd1:  begin
         sel_ok <= 16'b0000_0000_0000_0010 ;
    end
    4'd2:  begin
         sel_ok <= 16'b0000_0000_0000_0100 ;
    end
    4'd3:  begin
         sel_ok <= 16'b0000_0000_0000_1000 ;
    end

    4'd4:  begin
         sel_ok <= 16'b0000_0000_0001_0000 ;
    end
    4'd5:  begin
         sel_ok <= 16'b0000_0000_0010_0000 ;
    end
    4'd6:  begin
         sel_ok <= 16'b0000_0000_0100_0000 ;
    end
    4'd7:  begin
         sel_ok <= 16'b0000_0000_1000_0000 ;
    end

    4'd8:  begin
         sel_ok <= 16'b0000_0001_0000_0000 ;
    end
    4'd9:  begin
         sel_ok <= 16'b0000_0010_0000_0000 ;
    end
    4'd10:  begin
         sel_ok <= 16'b0000_0100_0000_0000 ;
    end
    4'd11:  begin
         sel_ok <= 16'b0000_1000_0000_0000 ;
    end

    4'd12:  begin
         sel_ok <= 16'b0001_0000_0000_0000 ;
    end
    4'd13:  begin
         sel_ok <= 16'b0010_0000_0000_0000 ;
    end
    4'd14:  begin
         sel_ok <= 16'b0100_0000_0000_0000 ;
    end
    4'd15:  begin
         sel_ok <= 16'b1000_0000_0000_0000 ;
    end
    endcase
end


/******************************************************/
//给显示逻辑的参数设置 在ahb   0xa100_0000 -0xa1ff_ffff
/******************************************************/
// assign set_d_ok = wr_en[1] && apb_sel[0]  && sel_ok[1] ;
always @(posedge sclk or negedge resetb) begin
    if (!resetb)
        set_d_ok <= 1'b0;
    else if (wr_en[1] && apb_sel[0]  && sel_ok[1])
        set_d_ok <= 1'b1;
    else 
        set_d_ok <= 1'b0;
end
assign set_addr = apb_addr[15:0]    ;
assign set_data =  apb_wdata[7:0]  ;
assign apb_rdata0 =  {sys_state_data,sys_state_data,sys_state_data,sys_state_data};


/******************************************************/
// ext_addr的参数设置   0x0100_0000~0x0100_FFFF   ahb:0xa200_0000 -0xa200_ffff
/******************************************************/
assign ext_d_ok[0] = wr_en[2] && apb_sel[0] &&  sel_ok[2]  ;

// always @(posedge sclk or negedge resetb) begin
    // if (!resetb)
        // ext_d_ok[0] <= 0;
    // else 
        // ext_d_ok[0] = wr_en_t && apb_sel[0] &&  sel_ok[2]  ;
// end

//************************************************/
//        reboot保护
//************************************************/
always @(posedge sclk or negedge resetb) begin
    if (!resetb)
        reboot_flag <= 1'b0;
    else if (ext_d_ok[0] == 1 && set_addr[7:2] == 6'h01)
        reboot_flag <= 1'b1;
    else if (reboot_cnt == 2'd0)
        reboot_flag <= 1'b0;
end

always @(posedge sclk or negedge resetb) begin
    if (!resetb)
        reboot_cnt <= 2'b0;
    else if (ext_d_ok[0] == 1 && set_addr[7:2] == 6'h01)
        reboot_cnt <= 2'd3;
    else if (time_1s && reboot_cnt != 2'b0)
        reboot_cnt <= reboot_cnt - 1'b1;
end

//************************************************/
//      reboot_sel
//************************************************/
always @(posedge sclk or negedge resetb)
    if (resetb == 0)
        reboot_sel <= 1'b0;
    else if (ext_d_ok[0] == 1 && set_addr[7:2] == 6'h01)
        reboot_sel <= apb_wdata[9:8];

//************************************************/
//        reconfig_pll_en
//************************************************/
always@(posedge sclk or negedge resetb)
    if (resetb == 0)
        reconfig_pll_en <=0;
    else if (reconfig_pll_en_dly)
        reconfig_pll_en<=0;
    else if (ext_d_ok[0] == 1 && set_addr[7:2] == 6'h01)
        reconfig_pll_en<=apb_wdata[24];

always@(posedge sclk)
    reconfig_pll_en_dly <= reconfig_pll_en;

/******************************************************/
// ext_addr的参数设置   0x1000_0000~0x1000_FFFF   ahb:0xa300_0000 -0xa000_ffff
/******************************************************/
assign ext_d_ok[1] = wr_en[3] && apb_sel[0] && sel_ok[3]  ;

// always @(posedge sclk or negedge resetb) begin
    // if (!resetb)
        // ext_d_ok[1] <= 0;
    // else 
        // ext_d_ok[1] = wr_en && apb_sel[0] &&  sel_ok[3]  ;
// end

always@(posedge sclk or negedge resetb)
    if (resetb == 0)
        reboot_en_tmp<=0;
    else if (ext_d_ok[1] == 1)
        reboot_en_tmp<=1;

always@(posedge sclk or negedge resetb)
    if (resetb == 0)
        reboot_en<=1'b0;
    else
        reboot_en<=reboot_en_tmp&&reboot_flag;



/******************************************************/
//id                 在ahb   0xa400_0000 -0xa400_0007
/******************************************************/
always @(posedge sclk)begin
    if (wr_en[4] && apb_sel[0] && sel_ok[4])
    case (set_addr[2])
        0: begin
            id[63:56] <= apb_wdata[7:0]; // year
            id[55:48] <= apb_wdata[15:8];  // month
            id[47:40] <= apb_wdata[23:16];  // day
            id[39:32] <= apb_wdata[31:24];
            end
        1:begin
            id[31:24] <= apb_wdata[7:0];
            id[23:16] <= apb_wdata[15:0];
            id[15:8]  <= apb_wdata[23:16];
            id[7:0]   <= apb_wdata[31:24];
          end
    endcase
end

always@(posedge sclk  or negedge resetb)begin
    if (resetb == 0)
        id_is_valid <= 1'b0;
    else if (wr_en[4] && apb_sel[0] &&  sel_ok[4] && set_addr[2] == 1'd1)
        id_is_valid <= 1'b1;
    else
        id_is_valid <= 1'b0;
end


/******************************************************/
//lock                 在ahb   0xa500_0000 -0xa500_0004
/******************************************************/
always @(posedge sclk)begin
    if (wr_en[5] && apb_sel[0] &&  sel_ok[5])
    case (set_addr[2])
        0: begin
            lock_enable <= (apb_wdata[7:0] == 'h3A);
            lock[31:24] <= apb_wdata[15:8];
            lock[23:16] <= apb_wdata[23:16];
            lock[15:8]  <= apb_wdata[31:24];
        end
        1: begin
            lock[7:0]   <= apb_wdata[7:0];
        end
    endcase
end

/******************************************************/
//com_ctrl控制   在ahb   0xa600_0000
/******************************************************/
always@(posedge sclk  or negedge resetb)begin
    if (resetb == 0)
        fpga_flag_next <= 0;
    else if (wr_en[6] && apb_sel[0] && sel_ok[6] && set_addr[3:0] == 4'b0 )
        fpga_flag_next <= apb_wdata[1:0];
end

always@(posedge sclk  or negedge resetb)begin
    if (resetb == 0)
        mcu_rec_end <= 0;
    else if (wr_en[6] && apb_sel[0] &&  sel_ok[6] && set_addr[3:0] == 4'd0 )
        mcu_rec_end    <= 1 ;
    else
        mcu_rec_end    <=  0;
end


/******************************************************/
//系统状态 在ahb   0xa700_0000
/******************************************************/
always@(posedge sclk  or negedge resetb)begin
    if (resetb == 0)
        init_mode <= 0;
    else if (wr_en[7] && apb_sel[0] &&  sel_ok[7] && set_addr[3:0] == 4'b0 )
        init_mode <= apb_wdata[0];
end

always@(posedge sclk or negedge resetb)begin
    if (resetb == 0)
        comm_en <= 0;
    else if (wr_en[7] && apb_sel[0] && sel_ok[7] && set_addr[3:0] == 4'd4 )
        comm_en <= apb_wdata[0];
end

always@(posedge sclk or negedge resetb)begin
    if (resetb == 0)
        O_adjust_start <= 0;
    else if (wr_en[7] && apb_sel[0] &&  sel_ok[7] && set_addr[3:0] == 4'd8 )
        O_adjust_start <= apb_wdata[0];
end

/******************************************************/
//key状态 在ahb   0xa900_0000
//key数据 在ahb   0xb000_0000
/******************************************************/

// assign ram_wr_rgb = wr_en[0] && apb_sel[1]  && sel_ok[0] ;
always@(posedge sclk or negedge resetb)begin
    if (resetb == 0)
        ram_wr_rgb <= 0;
    else 
        ram_wr_rgb <=  wr_en[0] && apb_sel[1]  && sel_ok[0] ;
end


assign ram_waddr_rgb = apb_addr[9:0]    ;
assign ram_wdata_rgb =  apb_wdata[31:0]  ;


always@(posedge sclk or negedge resetb)begin
    if (resetb == 0)
        key_out <= 0;
    else if (wr_en[9] && apb_sel[0] &&  sel_ok[9] && set_addr[3:0] == 4'd0)
        key_out <= apb_wdata[0] ;
    else 
        key_out <= 0;
end

//帧开始 中断， 60hz 16.67ms
reg [3:0] frame_start_reg;
always@(posedge sclk or negedge resetb)begin
    if ( resetb == 0 )
        frame_start_reg[3:0] <= 4'b0;
    else if( frame_start )
        // frame_start_reg[3:0] <= 4'b1111;
        frame_start_reg[3:0] <= frame_start_reg[3:0] + 1'b1 ;
    // else 
        // frame_start_reg[3:0] <= {1'b0 , frame_start_reg[3:1] } ;
end
assign GPIO2_I[5] = frame_start_reg[2] ;


//sdram 
//缓存在 0xb1000000
//操作   0xaa00_0000
//状态   0xd000_0000

assign      sdram_ram_data_w = apb_wdata[31:0] ;
assign      apb_rdata1   = sdram_ram_data_r;
assign      sdram_ram_addr = apb_addr[9:0]    ;

// always@(posedge sclk or negedge resetb)begin
    // sdram_ram_data_w <= apb_wdata[31:0] ;
    // sdram_ram_addr <= apb_addr[9:0]    ;
// end

// assign      sdram_ram_addr_wren = wr_en[1] && apb_sel[1]  && sel_ok[1] ;
always@(posedge sclk or negedge resetb)begin
    if (resetb == 0)
        sdram_ram_addr_wren <= 0;
    else if ( wr_en[1] && apb_sel[1]  && sel_ok[1] )
        sdram_ram_addr_wren <= 1 ;
    else 
        sdram_ram_addr_wren <= 0;
end

always@(posedge sclk or negedge resetb)begin
    if (resetb == 0)
        sdram_req <= 0;
    else if (wr_en[10] && apb_sel[0] &&  sel_ok[10] && set_addr[3:0] == 4'd0)
        sdram_req <= apb_wdata[0] ;
    else 
        sdram_req <= 0;
end

always@(posedge sclk or negedge resetb)begin
    if (resetb == 0)
        sdram_wr_or_rd <= 0;
    else if (wr_en[10] && apb_sel[0] &&  sel_ok[10] && set_addr[3:0] == 4'd4)
        sdram_wr_or_rd <= apb_wdata[0] ;
end

always@(posedge sclk or negedge resetb)begin
    if (resetb == 0)
        sdram_addr_start <= 0;
    else if (wr_en[10] && apb_sel[0] &&  sel_ok[10] && set_addr[3:0] == 4'd8)
        sdram_addr_start <= apb_wdata[23:0] ;
end

always@(posedge sclk or negedge resetb)begin
    if (resetb == 0)
        sdram_rw_len <= 'd256;
    else if (wr_en[10] && apb_sel[0] &&  sel_ok[10] && set_addr[3:0] == 4'd12)
        sdram_rw_len <= apb_wdata[10:0] ;
end

reg  [31:0]state_reg;
assign apb_rdata3 = state_reg;
always @(posedge sclk or negedge resetb)begin
    if (resetb == 0)
        state_reg <= 0 ;
    else if ( apb_sel[3] &&  sel_ok[0] )
        case(set_addr[7:0])
            8'h00: begin
                        state_reg[0] <= sdram_busy ;
                        state_reg[7:1] <= 1'b0 ;
                        state_reg[8] <= kp_busy ;
                        state_reg[15:9] <= 1'b0 ;
                        state_reg[31:16] <= 16'b0 ;
                   end
            default state_reg<='d0;
        endcase
end

/************************************************/
//        测试信号
/************************************************/
assign  tout = 0;

endmodule

